package ngat.oss.util;

import ngat.oss.*;
import ngat.phase2.*;
import ngat.phase2.nonpersist.*;
import ngat.util.*;
import ngat.astrometry.*;

import java.io.*;
import java.util.*;
import java.text.*;

import jyd.dbms.*;
import jyd.storable.*;
import jyd.collection.*;


public class JYDContention {
    
    public static void main (String[] args) {
	
	SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
	SimpleTimeZone   UTC = new SimpleTimeZone(0,"UTC");
	sdf.setTimeZone(UTC);

	try {
	    
	    CommandTokenizer parser = new CommandTokenizer("--");
	    parser.parse(args);
	    ConfigurationProperties config = parser.getMap();
	    
	    // mid-day of first night to test
	    long start = (sdf.parse(config.getProperty("start"))).getTime();
	    int days = config.getIntValue("days");
	    long end   = start * 86400L*1000*days;

	    double lat = config.getDoubleValue("lat");
	    double lon = config.getDoubleValue("long");
	    
	    Position.setViewpoint(Math.toRadians(lat), Math.toRadians(lon));
	    Site site = new Site("Test", lat, lon);

	    String dbDirName = System.getProperty("db.dir");
	    String dbRootName = System.getProperty("db.name");

	    OSS_Utilities.setDatabaseDir(new File(dbDirName));
	    OSS_Utilities.setRootName(dbRootName);
	    
	    System.err.println("Using: DB: "+dbRootName+" in dir: "+dbDirName);
	    
	    Transaction t = Transaction.current();
	    
	    Root root = OSS_Utilities.fetchRoot();
	    
	    // Check it exists.
	    if (root == null) {		
		System.err.println("Root: Not in database.");
		return;
	    } 
	    
	    for (int iday = 0; iday < days; iday++) {
		
		long sod = start + iday*86400*1000L;

		// length of night.
		Position sun = Astrometry.getSolarPosition(sod);

		long ln = 0L;
		long st = sod;
		while (st < sod + 86400*1000L) {
		    double sunElev = sun.getAltitude(st, site);
		    if (sunElev < Math.toRadians(-18.0))
			ln += 60000L;
		    st += 60000L;
		}
		double lnight = (double)ln;

		System.err.println("Day: "+iday+" "+sdf.format(new Date(sod))+" LN = "+(lnight/3600000.0)+" H");
		
		// record exec per date
		double time = 0.0;

		Iterator iTag = root.listAllTags();
		while (iTag.hasNext()) {
		    
		    Tag tag = (Tag)iTag.next();
		    
		    Iterator iUser = tag.listAllUsers();
		    while (iUser.hasNext()) {
			
			User user = (User)iUser.next();
			
			Iterator iProp = user.listAllProposals();
			while (iProp.hasNext()) {
			    
			    KVPair pair = (KVPair)iProp.next();
			    String name = (String)pair.getKey();
			    Path   path = new Path(user.getFullPath(), name);
			    Proposal proposal = null;
			    try {
				proposal = OSS_Utilities.fetchProposal(path);
			    } catch (IOException iox) {
				System.err.println("Skipping Proposal: "+path.toString()+
						   " Error fetching from Database: "+iox);	
				continue;
			    }		
			    
			    if (proposal == null)
				continue;
			    
			    if (proposal.getActivationDate() > sod ||
				proposal.getExpiryDate() < sod) 
				continue;
			    
			    if (proposal.getUsedTime() >= proposal.getAllocatedTime())
				continue;
			    
			    
			    System.err.println("Using proposal: "+proposal);
			    Iterator iGroup = proposal.listAllGroups();
			    while (iGroup.hasNext()) {
			
				Group group = (Group)iGroup.next();
			
				double gx = group.getNominalExecutionTime();
			
			
				// Now check we are able to do group today
				
				if (group.getExpiryDate() < sod)
				    continue;
					
				// work out visibility now (but only during darkness period)
				double vis = 0.0;
				long tt = sod;
				while (tt < sod + 86400*1000L) {	
				    if (cando(group, tt)) {
					double sunElev = sun.getAltitude(tt, site);
					if (sunElev < Math.toRadians(-18.0)) {
					    vis += 60000.0;
					}
				    }
				    tt += 60000L;
				}
				
				System.err.println("Found visible group: "+group.getFullPath()+" Exec = "+(gx/1000)+" S, VISFRAC = "+(vis/lnight));
				
				if (group instanceof MonitorGroup) {
				    // MONITOR
				   
				    if (((MonitorGroup)group).getStartDate() > sod)
					continue;
				    if (((MonitorGroup)group).getEndDate() < sod)
					continue;
				    double period = (double)((MonitorGroup)group).getPeriod();
				    double nw = vis / period;
				    time += gx*nw;
				    
				} else if 
				      (group instanceof RepeatableGroup) {
				    // MIN INTERVAL
				    if (((RepeatableGroup)group).getStartDate() > sod)
					continue;
				    if (((RepeatableGroup)group).getEndDate() < sod)
					continue;

				    double minint = (double)((RepeatableGroup)group).getMinimumInterval();
				    double nw = vis / minint;
				    time += gx*nw;
				    
				} else if
				      (group instanceof EphemerisGroup) {
				    // EPHEMERIS  
				    if (group.isDone())
					continue;
				    if (((EphemerisGroup)group).getStart() > sod)
					continue;
				    if (((EphemerisGroup)group).getEnd() < sod)
					continue;

				    time += vis*gx/lnight;
				    

				} else if
				      (group instanceof FixedGroup) {
				    // FIXED

				    long fgt = ((FixedGroup)group).getFixedTime();
				    if (fgt < sod || fgt > sod+86400*1000L)
					continue;
				    
				     time += gx;

				} else {
				    // FLEXIBLE

				    if (group.isDone())
					continue;
				    // check its out of date...
				    if (group.getStartingDate() > sod ||
					group.getExpiryDate() < sod)
					continue;

				    // no nights left...
				    double nrn = (double)(group.getExpiryDate() - sod)/86400000.0;
				    // note we get just a fraction contribution
				    time =+ gx/nrn;

				}

			    } // next Group
			    
			} // next Proposal
			
		    } // next User
		    
		} // next TAG

		System.err.println("TOTEX " +sdf.format(new Date(sod))+" "+(time/3600000.0)+" H "+(time/lnight));


	    } // next day

	} catch (Exception e) {
	    e.printStackTrace();
	    return;
	}
    }

    /** check all targets visible.*/
    private static boolean cando(Group group, long now) {

	// check target visibility.
	Iterator it = group.listAllObservations();
	while (it.hasNext()) {
	    Observation obs = (Observation)it.next();
	    if (obs != null) {
		Source source = obs.getSource();
		Position target = source.getPosition();
		if (target.getAltitude(now) < Math.toRadians(22.0))
		    return false;
	    }
	}

	return true;
	
    }
        
}
